package upload;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;

/**
 * This class is the streaming server, which handles POST requests.
 * @author Romain Pellerin
 */
public class Server extends Thread {
	private static int PORT;
	
	private ServerSocket serverSocket;
	private boolean sockeClosed = false;
	private HashSet<Socket> openedSockets = new HashSet<Socket>();
	
	/**
	 * Default constructor. The server will listen on port 8081.
	 */
	public Server() {
		this(8081);
	}
	
	/**
	 * Constructor
	 * @param port The port to listen on.
	 */
	public Server(int port) {
		Server.PORT = port;
		this.setName("Streaming server");
	}
	
	@Override
	public void run() {
		System.out.println("Streaming server has just started. Listenning on "+PORT+"...");
		try {
			serverSocket = new ServerSocket(PORT);
			while (true) {
				System.out.println("Waiting for someone");
				Socket clientSocket = serverSocket.accept();	// Waiting for someone
				System.out.println("Connection");
				clientSocket.setSoTimeout(1000);
				addOpenedSocket(clientSocket);
				(new Request(clientSocket,this)).start();		// Handles the client
			}
		}
		catch (IOException e) {
			if (!sockeClosed) {
				System.out.println("Exception caught when trying to listen on port "+PORT+" or listening for a connection");
				System.out.println(e.getMessage());
			}
		}
		finally {
			System.err.println("STREAMING SERVER HAS SHUTDOWN");
			try {
				if (serverSocket != null) serverSocket.close();
			} catch (Exception e) {/*ignore*/}
		}
	}

	/**
	 * Kill the waiting socket if it exists
	 */
	public synchronized void killSocket() {
		if (this.serverSocket != null && !this.serverSocket.isClosed()) {
			this.sockeClosed = true;
			try {
				this.serverSocket.close();
			} catch (Exception e) {/*ignore*/}
			for (Socket s : this.openedSockets) {
				try {s.close();} catch (Exception e) {/*ignore*/}
				removeOpenedSocket(s);
			}
		}
	}
	
	/**
	 * Add a open {@link Socket} to the list
	 * @param socket The new {@link Socket} to add
	 */
	private synchronized void addOpenedSocket(Socket socket) {
		this.openedSockets.add(socket);
	}
	
	/**
	 * Remove a closed {@link Socket} from the list
	 * @param socket The {@link Socket} to remove
	 */
	public synchronized void removeOpenedSocket(Socket socket) {
		this.openedSockets.remove(socket);
	}
	
}
